package com.bkgy.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.bulk.BulkWriteResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * mongodb操作数据库的工具类
 */
@Slf4j
@Component
public class MongoUtils {

    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 数据存在 则跳过，数据不存在 则新增
     * @param dataList
     * @param entityClass
     * @param primaryKey
     * @param <T>
     */
    public <T> void bulkInsert(List<T> dataList, Class<T> entityClass, String primaryKey) {
        if (dataList.isEmpty()) return;

        BulkOperations bulkOps = mongoTemplate.bulkOps(
                BulkOperations.BulkMode.ORDERED, // 保持有序模式避免唯一索引并发冲突
                entityClass
        );

        ObjectMapper objectMapper = new ObjectMapper();

        dataList.forEach(entity -> {
            Map<String, Object> fieldMap = objectMapper.convertValue(entity, Map.class);
            Object volumeValue = fieldMap.remove(primaryKey);

            // 构建仅插入时生效的 Update 对象
            Update update = new Update();
            fieldMap.forEach((key, value) -> update.setOnInsert(key, value)); // 关键修改点[6,8](@ref)

            Query query = Query.query(Criteria.where(primaryKey).is(volumeValue));
            bulkOps.upsert(query, update); // upsert: true 自动生效
        });

        try {
            BulkWriteResult result = bulkOps.execute();
            log.info("批量操作完成，新增文档数量: {}", result.getUpserts().size());
        } catch (Exception e) {
            log.error("异常信息: {}", e.getMessage(), e);
        }
    }

    /**
     * 批量操作数据更新或插入数据
     *
     * @param dataList
     * @param entityClass
     * @param primaryKey
     * @param <T>
     */
    public <T> void bulkUpsertByIndex(List<T> dataList, Class<T> entityClass,String primaryKey) {
        if (dataList.isEmpty()) return;
        //创建 MongoDB 的批量操作对象
        BulkOperations bulkOps = mongoTemplate.bulkOps(
                BulkOperations.BulkMode.ORDERED,
                entityClass
        );

        ObjectMapper objectMapper = new ObjectMapper();

        dataList.forEach(entity -> {
            // 动态转换实体为Map并移除主键
            Map<String, Object> fieldMap = objectMapper.convertValue(entity, Map.class);
            Object volumeValue = fieldMap.remove(primaryKey);

            // 构建全字段更新（自动排除主键）
            Update update = new Update();
            fieldMap.forEach(update::set);

            // 基于唯一索引构建查询条件[1](@ref)
            Query query = Query.query(Criteria.where(primaryKey).is(volumeValue));
            bulkOps.upsert(query, update);
        });

        // 执行批量操作并记录结果
        try {
            BulkWriteResult result = bulkOps.execute();
            log.info("批量操作完成，entityClass:[{}] 匹配到的更新文档数量: {}, 新增的新文档数量: {}", entityClass.getSimpleName(),result.getMatchedCount(), result.getUpserts().size());
        } catch (Exception e) {
            log.error("异常信息 Bulk upsert failed: {}", e.getMessage(), e);
        }
    }

    /**
     * 根据字段primaryKey校验数据是否存在 存在则更新 不存在 则插入
     * @param entity
     * @param entityClass
     * @param primaryKey
     * @param <T>
     */
    public <T> void upsertSingleDocument(T entity, Class<T> entityClass, String primaryKey) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();

            // 步骤1：转换实体为Map并提取主键值
            Map<String, Object> fieldMap = objectMapper.convertValue(entity, Map.class);
            Object primaryValue = fieldMap.remove(primaryKey);

            // 步骤2：构建全字段更新对象
            Update update = new Update();
            fieldMap.forEach(update::set);

            // 步骤3：基于主键构建查询条件
            Query query = Query.query(Criteria.where(primaryKey).is(primaryValue));

            // 步骤4：执行单文档 Upsert
            mongoTemplate.upsert(query, update, entityClass);

        } catch (Exception e) {
            log.error("单文档操作失败: {}", e.getMessage());
            throw new RuntimeException("数据持久化异常", e);
        }
    }
    public <T> void insertIfNotExists(T entity, Class<T> entityClass, String primaryKey) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();

            // 步骤1：转换实体为Map并提取主键值
            Map<String, Object> fieldMap = objectMapper.convertValue(entity, Map.class);
            Object primaryValue = fieldMap.remove(primaryKey);

            // 步骤2：构建仅插入时生效的更新对象
            Update update = new Update();
            fieldMap.forEach((key, value) -> update.setOnInsert(key, value)); // 关键修改点

            // 步骤3：基于主键构建查询条件
            Query query = Query.query(Criteria.where(primaryKey).is(primaryValue));

            // 步骤4：执行 Upsert（存在则跳过，不存在则插入）
            mongoTemplate.upsert(query, update, entityClass);

        } catch (Exception e) {
            log.error("单文档操作失败: {}", e.getMessage());
            new RuntimeException("数据持久化异常", e);
        }
    }

}
